import FileOperate.FileOperate;
import ParseSystemUtil.ParseSystemUtil;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

final class DESEncryptTools {
    //加密算是是des
    private static final String ALGORITHM = "DES";
    //转换格式
    private static final String TRANSFORMATION = "DES/ECB/PKCS5Padding";
    /* DES在实际应用中有多种模式（ECB、CBC、CBR等）和填充方式（PKCS5Padding、NoPadding、ZeroPadding）
       此处以最为广泛使用的ECB模式、PKCS5填充举例
    */
    //利用8个字节64位的key给src加密
    @SuppressWarnings("unused")
    public static byte[] encrypt(byte[] src, byte[] key) {//加密函数
        try {
            //加密
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            KeySpec keySpec = new DESKeySpec(key);
            SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new SecureRandom());
            byte[] enMsgBytes = cipher.doFinal(src);
            return enMsgBytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //利用8个字节64位的key给src解密
    @SuppressWarnings("unused")
    public static byte[] decrypt(byte[] encryptBytes, byte[] key) {//解密函数
        try {
            //解密
            //Cipher deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            Cipher deCipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeyFactory deDecretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            KeySpec deKeySpec = new DESKeySpec(key);
            SecretKey deSecretKey = deDecretKeyFactory.generateSecret(deKeySpec);
            deCipher.init(Cipher.DECRYPT_MODE, deSecretKey, new SecureRandom());
            byte[] deMsgBytes = deCipher.doFinal(encryptBytes);
            return deMsgBytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class DesMainTest {
    private static String key = "12345678";//密钥

    public static void main(String[] args) throws Exception {
        System.out.println("DES密钥算法测试：");
        String msg = null;
        try {
            msg = FileOperate.fileRead("D:\\IDEA_java\\src\\DES\\test.txt");
            System.out.println("文件读取成功，明文为：" + msg);
            System.out.println("明文长度：" + msg.getBytes().length * 8+"bit");
            System.out.println("密钥长度：" + key.getBytes().length * 8+"bit");
        } catch (Exception e) {
            System.out.println(e.getMessage().toString());
        }
        long startTime = System.nanoTime();
        byte[] encryptBytes = DESEncryptTools.encrypt(msg.getBytes(), key.getBytes());
        String hexStrResult = ParseSystemUtil.parseByte2HexStr(encryptBytes);
        System.out.println("加密后的16进制密文为：" + hexStrResult);
        // 此处密文长度计算不可用String类型的hexStrResult求长度，必须用Byte[]型的encryptBytes
        System.out.println("密文长度：" + returnActualLength(encryptBytes) * 8+"bit");
        long endTime = System.nanoTime();
        System.out.println("加密耗时：" + (endTime - startTime) + "ns");
        try {
            FileOperate.fileWrite("D:\\IDEA_java\\src\\DES\\密文.txt", new String(encryptBytes));
        } catch (Exception e) {
            System.out.println(e.getMessage().toString());
        }
        startTime = System.nanoTime();
        byte[] deMsgBytes = DESEncryptTools.decrypt(encryptBytes, key.getBytes());
        System.out.println("解密后的明文为:" + new String(deMsgBytes));
        endTime = System.nanoTime();
        System.out.println("明文长度：" + returnActualLength(deMsgBytes) * 8+"bit");
        System.out.println("解密耗时：" + (endTime - startTime) + "ns");
        try {
            FileOperate.fileWrite("D:\\IDEA_java\\src\\DES\\明文.txt", new String(deMsgBytes));
        } catch (Exception e) {
            System.out.println(e.getMessage().toString());
        }
    }

    public static int returnActualLength(byte[] data) {//计算Byte[]到底占用几个字节
        int i = 0;
        for (; i < data.length; i++) {
            if (data[i] == '\0')
                break;
        }
        return i;
    }
}
